package pe.com.hermes.hermetic.negocio.managerimpl.pedido.atm;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import java.util.Locale;
import java.util.Map;

import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.context.support.ResourceBundleMessageSource;

import pe.com.hermes.hermetic.negocio.service.PedidoService;
import pe.com.hermes.hermetic.negocio.ultil.ConstantesHermetic;
import pe.com.hermes.hermetic.negocio.ultil.Util;
import pe.com.hermes.unidadesnegocio.boveda.entities.BovedaEntity;
import pe.com.hermes.unidadesnegocio.comercial.entities.AtmEntity;
import pe.com.hermes.unidadesnegocio.comercial.entities.ClienteEntity;
import pe.com.hermes.unidadesnegocio.comercial.entities.ClienteGrupoEntity;
import pe.com.hermes.unidadesnegocio.comercial.entities.PuntoEntity;
import pe.com.hermes.unidadesnegocio.general.entities.TipoEntity;
import pe.com.hermes.unidadesnegocio.general.response.common.CampoResponse;
import pe.com.hermes.unidadesnegocio.general.response.pedido.PedidoResponse;
import pe.com.hermes.unidadesnegocio.procesamiento.entities.PedidoDenoEntity;
import pe.com.hermes.unidadesnegocio.procesamiento.entities.PedidoDetaEntity;
import pe.com.hermes.unidadesnegocio.procesamiento.managerimpl.PedidoAbstract;

public class PedidoAtmManagerImpl extends PedidoAbstract {
    private PedidoService pedidoService;
    private ResourceBundleMessageSource messageSource;
    private Map<String,Integer> mapBoveByUnidMoneAndTipMone = new HashMap<String,Integer>();
    protected final static Map<String,PedidoDenoEntity> DENOS_DETA_PEDIDO = new HashMap<String,PedidoDenoEntity>();
    protected Log logger = LogFactory.getLog(this.getClass());
    public static final Comparator<PedidoAbstract> ORDER_BY_CONF_DISP = new Comparator<PedidoAbstract>() {
    public int compare(PedidoAbstract e1, PedidoAbstract e2) {
        int a = ((AtmEntity)e1.getPunt()).hashConfiguracionDisp();
        int b = ((AtmEntity)e2.getPunt()).hashConfiguracionDisp();
          return String.valueOf(a).compareTo(String.valueOf(b));
      }
    };
    public PedidoAtmManagerImpl(){
        this.savePedidoDenoDeta = true;
        this.indOrig = IND_ORIG_HW;
        this.billetaje = new TipoEntity(ConstantesHermetic.TIP_BILL_ATM,ConstantesHermetic.TIP_BILL_ATM_DESC);
        this.tipPedi = new TipoEntity(ConstantesHermetic.TIPO_PEDIDO_ATM);
        this.indPediBanc = Integer.parseInt(ConstantesHermetic.TIPO_PEDI_BANC);
        this.codTrnp = Integer.valueOf(ConstantesHermetic.COD_TRNP);
        this.usuCrea = ConstantesHermetic.USER_GEN;        
        this.tipRegiPedi = TIP_REG_PEDI_INDI;  
        this.useIndPrioInsteadOfHorInicPact = true;
        this.tipProc= new TipoEntity(TIP_PROC_ATM);
    }
    public void setPedidoService(PedidoService pedidoService) {
        this.pedidoService = pedidoService;
    }
    @Override
    public void isValidFecProcAper() {
        CampoResponse campoResponse = new CampoResponse(); 
        //super.isValidFecProcAper(); 
        if(pedidoResponse.campoHasError("fecProcAper"))
          return;
        else{
          campoResponse = pedidoService.validaFecProc(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(cuentaOrig.getCodCnta()),String.valueOf(punt.getCodPunt()),fecProcAper);
          String label = messageSource.getMessage("fecProcAper.label",null, Locale.US);
          campoResponse.setSMens(label+": "+campoResponse.getSMens());
          campoResponse.setSCampo("fecProcAper-"+idPedido);
          pedidoResponse.getCamposResponse().add(campoResponse);
        }
    }
    @Override
    public void areValidMontos() {
        List<CampoResponse> list = new ArrayList<CampoResponse>();
        String sCampo = null;
        CampoResponse campoResponse = new CampoResponse(); 
        if(denosDetaPedido==null)
            return;
        
        Collection<PedidoDenoEntity> listDenoySaldAtm = pedidoService.getListDenoYSaldAtm(clieOrig.getCodClie(), sucuHtb.getCodSucuHtb(), cuentaOrig.getCodCnta(), fecProcAper, punt.getCodPunt(), Integer.valueOf(billetaje.getCodTipo()));        
        for(PedidoDenoEntity pedidoDeno:listDenoySaldAtm){
            DENOS_DETA_PEDIDO.put(pedidoDeno.getIdPedidoDenoAtm(), pedidoDeno);
        }        
        for(PedidoDenoEntity denoPedido:denosDetaPedido){
            String idPedidoDeno = denoPedido.getIdPedidoDenoAtm();
            try{ 
                denoPedido.getDispensador().getDeno().setCanValoNomi(DENOS_DETA_PEDIDO.get(idPedidoDeno).getDispensador().getDeno().getCanValoNomi());
            }catch(Exception e){
                logger.error(e);
                list.add(new CampoResponse(CampoResponse.RESPONSE_ERROR,"","Montos y Denominaciones: Existen denominaciones no asociadas al cajero, comuniquese con contraloria"));
                continue;
            }
          sCampo = "d"+denoPedido.getUnidMone().getCodTipo()+denoPedido.getTipMone().getCodTipo()+denoPedido.getTipMone().getCodTipo()+denoPedido.getDispensador().getDeno().getCodDeno()+denoPedido.getDispensador().getNumDisp()+"-"+idPedido;
            if(denoPedido.getMontDeno()>0){
              campoResponse = pedidoService.validaMontoDispen(String.valueOf(sucuHtb.getCodSucuHtb()), String.valueOf(clieOrig.getCodClie()), String.valueOf(cuentaOrig.getCodCnta()), String.valueOf(punt.getCodPunt()), String.valueOf(denoPedido.getDispensador().getNumDisp()), String.valueOf(denoPedido.getUnidMone().getCodTipo()), denoPedido.getDispensador().getDeno().getCanValoNomi(), fecProcAper, denoPedido.getMontDeno());
              String label = denoPedido.getUnidMone().getDesTipo()+" "+Util.getDoubleFormatted(denoPedido.getDispensador().getDeno().getCanValoNomi());
              campoResponse.setSMens(label+": "+campoResponse.getSMens());
              campoResponse.setSCampo(sCampo);
              list.add(campoResponse);  
            }
        }
        if(!isMontDenoGreaterThanZero()){
          list.add(new CampoResponse(CampoResponse.RESPONSE_ERROR,"","Monto Total: El monto del pedido debe ser mayor que 0"));
        }
        pedidoResponse.getCamposResponse().addAll(list);
    }

    @Override
    public void isValidFecAtenPedi() {
      CampoResponse campoResponse = new CampoResponse();
      super.isValidFecAtenPedi(); 
      if(pedidoResponse.campoHasError("fecAtenPedi"))
        return;
      else{
        campoResponse = pedidoService.validaFecAten(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(punt.getCodPunt()),fecAtenPedi);
        String label = messageSource.getMessage("fecAtenPedi.label",null, Locale.US);
        campoResponse.setSMens(label+": "+campoResponse.getSMens());
        campoResponse.setSCampo("fecAtenPedi-"+idPedido);
        pedidoResponse.getCamposResponse().add(campoResponse);
        }
    }

    @Override
    public void isValidHorAtenInicPact() {
      CampoResponse campoResponse = new CampoResponse();
      super.isValidHorAtenInicPact();
      String label = messageSource.getMessage("horAtenInicPact.label",null, Locale.US);
      if(pedidoResponse.campoHasError("horAtenInicPact"))
        return;
      Map map = pedidoService.validaHoraAten(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(punt.getCodPunt()),fecAtenPedi, horAtenInicPact);
      campoResponse =  (CampoResponse)map.get("rpta");
      String indPrio = null;
      Integer tipPrio = 0;
      if(!campoResponse.isEmptyMessages()){
          campoResponse.setSMens(label+": "+campoResponse.getSMens());
          campoResponse.setSCampo("horAtenInicPact-"+idPedido);
          pedidoResponse.getCamposResponse().add(campoResponse);
          return;
          }
        if(map.get("codPrio")!=null)
          indPrio = map.get("codPrio").toString(); 
        if(map.get("tipPrio")!=null)
          tipPrio = (Integer)map.get("tipPrio");
        campoResponse = pedidoService.validaHoraAtenParam(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(punt.getCodPunt()),fecAtenPedi, horAtenInicPact, indPrio, tipPrio);
        campoResponse.setSMens(label+": "+campoResponse.getSMens());
        campoResponse.setSCampo("horAtenInicPact-"+idPedido);
        pedidoResponse.getCamposResponse().add(campoResponse);
    }

    public PedidoService getPedidoService() {
        return pedidoService;
    }

    public void setMessageSource(ResourceBundleMessageSource messageSource) {
        this.messageSource = messageSource;
    }
  /*
    public PedidoResponse completePedidoInfo() {
        PedidoResponse pedidoResponse = new PedidoResponse();
        codSeriPedi = getCodSeriPedi(sucuHtb.getCodSucuHtb());
        tipDocuPedi = obtainTipDocu();
        numPedi = obtainNumPedi();
        indProg = pedidoService.getIndProgAtm(punt.getCodPunt(), fecAtenPedi, horAtenInicPact, horFinlInicPact);
        punt = obtainPunt();        
        clieFact = new ClienteEntity(pedidoService.getCodClieFact(punt.getCodPunt(), clieOrig.getCodClie(), clieGrup.getCodClie(), sucuHtb.getCodSucuHtb(), cuentaOrig.getCodCnta()));
        tipDestPedi = (clieGrup.getCodClie().intValue()==clieOrig.getCodClie().intValue()?"1":"2");        
        tipPrio = obtainTipPrio();
        nomComp = obtainNomComp();
        indPediAtmCont = obtainIndPediAtmCont();
        detasPedido= obtainPedidoDeta();
        denosDetaPedido= obtainPedidoDenoDeta();
        denosPedido= obtainPedidoDeno();
        pedidoResponse.setCamposResponse(areValidBovedas());        
        pedidoResponse.calculaResu();       
        return pedidoResponse;
    }
  */
    public void areValidBovedas(){
        List<CampoResponse> list = new ArrayList<CampoResponse>();
        Map<String,Set<Integer>> mapBoves = bovedasToSave();
        for(Map.Entry<String,Set<Integer>> entry:mapBoves.entrySet()){
            CampoResponse campoResponse = new CampoResponse();
            if(entry.getValue().contains(new Integer(0))){
                campoResponse.setSResult(CampoResponse.RESPONSE_ERROR);
                campoResponse.setSMens("Error al obtener las bovedas para la unidad monetaria de codigo: "+entry.getKey());                
            }
            list.add(campoResponse);
        }
        pedidoResponse.getCamposResponse().addAll(list);
    }
    public Map<String,Set<Integer>> bovedasToSave(){
        Map<String,Set<Integer>> mapBove = new HashMap<String,Set<Integer>>();
        Map<String,Set<Integer>> mapTipMone = unidMonesAndTipMone();        
        for(Map.Entry<String,Set<Integer>> entry:mapTipMone.entrySet()){
            String unidMone = entry.getKey();
            Set<Integer> bovedaList = new HashSet<Integer>();
            for(Integer tipMone:entry.getValue()){                
                int codBove = pedidoService.getBovedaDePedido(clieOrig.getCodClie(),sucuHtb.getCodSucuHtb(),cuentaOrig.getCodCnta(),Integer.valueOf(unidMone),tipMone);
                bovedaList.add(codBove);
                mapBoveByUnidMoneAndTipMone.put(unidMone+"-"+tipMone, codBove);
            }
            mapBove.put(unidMone, bovedaList);
        }
        return mapBove;
    }
    public Map<String,Set<Integer>> unidMonesAndTipMone(){
      Map<String,Set<Integer>> map = new HashMap<String,Set<Integer>>();
      Set<String> unidMoneList = new HashSet<String>(); 
      for(PedidoDenoEntity pedidoDeno:denosDetaPedido){
          unidMoneList.add(pedidoDeno.getUnidMone().getCodTipo());          
      }
      for(String unidMone:unidMoneList){
        Set<Integer> tipMoneList = new HashSet<Integer>();
        for(PedidoDenoEntity pedidoDeno:denosDetaPedido){
            if(unidMone.equals(pedidoDeno.getUnidMone().getCodTipo())){
                tipMoneList.add(Integer.valueOf(pedidoDeno.getTipMone().getCodTipo()));
            }
        }
        map.put(unidMone, tipMoneList);    
      }      
      return map;    
    }
    public Collection<PedidoDetaEntity> obtainPedidoDeta(){
        Collection<PedidoDetaEntity> detasPedido = new ArrayList<PedidoDetaEntity>();
        Map<String,Set<Integer>> mapBoves = bovedasToSave();
        int numSecu = 1;
        for(Map.Entry<String,Set<Integer>> entry:mapBoves.entrySet()){            
            for(Integer codBove:entry.getValue()){
                double montDeta = 0;
                PedidoDetaEntity pedidoDetaEntity = new PedidoDetaEntity();
                pedidoDetaEntity.setNseItemPedi(numSecu);
                pedidoDetaEntity.setBilletaje(billetaje);
                pedidoDetaEntity.setBoveda(new BovedaEntity(codBove));                
                pedidoDetaEntity.setCodSeriPedi(codSeriPedi);
                pedidoDetaEntity.setTipDocuPedi(tipDocuPedi);
                pedidoDetaEntity.setUsuCrea(usuCrea);
                pedidoDetaEntity.setUsuWeb(usuWeb);
                pedidoDetaEntity.setNomComp(nomComp);
                for(Map.Entry<String,Integer> entryBoveByUnidMoneAndTipMone : mapBoveByUnidMoneAndTipMone.entrySet()){
                    String _unidMone = entryBoveByUnidMoneAndTipMone.getKey().split("-")[0];
                    String _tipMone = entryBoveByUnidMoneAndTipMone.getKey().split("-")[1];
                    int _codBove = entryBoveByUnidMoneAndTipMone.getValue();
                    for(PedidoDenoEntity pedidoDeno:denosDetaPedido){
                        if(_unidMone.equals(pedidoDeno.getUnidMone().getCodTipo())&&_tipMone.equals(pedidoDeno.getTipMone().getCodTipo())&&codBove ==_codBove){
                            montDeta += pedidoDeno.getMontDeno();
                            pedidoDeno.setNseItemPedi(numSecu);
                        }
                    }
                }
                pedidoDetaEntity.setMontPedi(montDeta);
                //JRIVERA Cambio para grabar bovedas con cero por dispensadores inactivos- ATM
                //if(montDeta>0){
                    numSecu++;
                    detasPedido.add(pedidoDetaEntity);
                    pedidoDetaEntity.setNumPedi(numPedi);
                //}
            }
        }
        return detasPedido;
    }    
    @Override
    public Integer obtainNumPedi() {
        int numPedi = pedidoService.getNumPedi(tipDocuPedi,codSeriPedi)+1;
        pedidoService.inseTgCtrlNume(tipDocuPedi,codSeriPedi,numPedi);
        return numPedi;
    }

    @Override
    public void isValidCuentaDest() {
    }

    @Override
    public void isValidClieDest() {
    }

    @Override
    public void isValidCodDiarPedi() {
    }

    private PuntoEntity obtainPunt() {        
        return punt;
    }

    @Override
    public void isValidIndPrio() {
        CampoResponse campoResponse = new CampoResponse(); 
        super.notEmptyIndPrio();
        Map map = pedidoService.validaHoraAten(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(punt.getCodPunt()),fecAtenPedi, this.indPrio.getCodTipo());
        try {
            String rangoHorario = map.get("rangoHorario").toString();
            this.horAtenInicPact = rangoHorario.split("-")[0];
            this.horFinlInicPact = rangoHorario.split("-")[1];
        } catch (Exception e) {
            // TODO: Add catch code
            e.printStackTrace();
        }
        campoResponse =  (CampoResponse)map.get("rpta");
        String indPrio = null;
        Integer tipPrio = 0;
        if(!campoResponse.isEmptyMessages()){
            pedidoResponse.getCamposResponse().add(campoResponse);
            return;
        }
        if(map.get("codPrio")!=null)
          indPrio = map.get("codPrio").toString(); 
        if(map.get("tipPrio")!=null)
          tipPrio = (Integer)map.get("tipPrio");
        campoResponse = pedidoService.validaHoraAtenParam(String.valueOf(sucuHtb.getCodSucuHtb()),String.valueOf(clieOrig.getCodClie()),String.valueOf(punt.getCodPunt()),fecAtenPedi, horAtenInicPact, indPrio, tipPrio);
        String label = messageSource.getMessage("horAtenInicPact.label",null, Locale.US);
        campoResponse.setSMens(label+": "+campoResponse.getSMens());
        campoResponse.setSCampo("indPrio-"+idPedido);
        pedidoResponse.getCamposResponse().add(campoResponse);
    }

    @Override
    public int obtainIndPediAtmCont() {
        return pedidoService.getIndConfAtmAuto(punt.getCodPunt(),clieOrig.getCodClie());
    }

    @Override
    public void isValidCuentaOrig() {
        CampoResponse campoResponse = new CampoResponse();
        super.isValidCuentaOrig();
        if(!pedidoService.isCuentaAtm(clieOrig.getCodClie(), sucuHtb.getCodSucuHtb(), cuentaOrig.getCodCnta())){
            campoResponse.setSResult(CampoResponse.RESPONSE_ERROR);
            campoResponse.setSMens("La cuenta ingresada no esta asociada a una cuenta ATM, por favor comunicarse con contraloria");
        }
        pedidoResponse.getCamposResponse().add(campoResponse);
    }

    @Override
    public void completeInfoToInsertPedido() {
        codSeriPedi = getCodSeriPedi(sucuHtb.getCodSucuHtb());
        tipDocuPedi = obtainTipDocu();
        indProg = pedidoService.getIndProgAtm(punt.getCodPunt(), fecAtenPedi, horAtenInicPact, horFinlInicPact);
        punt = obtainPunt();        
        clieFact = new ClienteEntity(pedidoService.getCodClieFact(punt.getCodPunt(), clieOrig.getCodClie(), clieGrup.getCodClie(), sucuHtb.getCodSucuHtb(), cuentaOrig.getCodCnta()));
        tipDestPedi = (clieGrup.getCodClie().intValue()==clieOrig.getCodClie().intValue()?"1":"2");        
        tipPrio = obtainTipPrio();
        nomComp = obtainNomComp();
        indPediAtmCont = obtainIndPediAtmCont();
        detasPedido= obtainPedidoDeta();
        denosDetaPedido= obtainPedidoDenoDeta();
        denosPedido= obtainPedidoDeno();
    }
}
